package com.hengpeng.itfin.common;

/**
 * union
 * version 1.0
 * auto:linxj
 * data:2011-11-18
 * 本程序主要是des及3des的加解密
 * UnionDesEncrypt及UnionDesDecrypt为des加解密
 * Union3DesEncrypt及Union3DesDecrypt为3des加解密
 */
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;

public class UnionDes
{

	static String DES = "DES/ECB/NoPadding";

	static String TriDes = "DESede/ECB/NoPadding";

	/**
	 * 十六进制字符串转二进制
	 * @param str 十六进制串
	 * @return
	 */
	public static byte[] hex2byte(String str)
	{ // 字符串转二进制
		int len = str.length();
		String stmp = null;
		byte bt[] = new byte[len / 2];
		for (int n = 0; n < len / 2; n++)
		{
			stmp = str.substring(n * 2, n * 2 + 2);
			bt[n] = (byte) (java.lang.Integer.parseInt(stmp, 16));
		}
		return bt;
	}

	/**
	 * 二进制转十六进制字符串
	 * @param b
	 * @return
	 */
	public static String byte2hex(byte[] b)
	{ // 二行制转字符串
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++)
		{
			stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
			if (stmp.length() == 1)
			{
				hs = hs + "0" + stmp;
			}
			else
			{
				hs = hs + stmp;
			}
			if (n < b.length - 1)
			{
				hs = hs + "";
			}
		}
		return hs.toUpperCase();
	}

	public static char asctohex(char ch1, char ch2)
	{
		char ch;
		if (ch1 >= 'A')
			ch = (char) ((ch1 - 0x37) << 4);
		else
			ch = (char) ((ch1 - '0') << 4);
		if (ch2 >= 'A')
			ch |= ch2 - 0x37;
		else
			ch |= ch2 - '0';
		return ch;
	}

	public static String aschex_to_bcdhex(String aschex, int len)
	{
		int i, j;
		String bcdhex = "";

		if (len % 2 == 0)
			j = len / 2;
		else
			j = len / 2 + 1;

		for (i = 0; i < j; i++)
			// bcdhex += asctohex(aschex[2*i],aschex[2*i+1]);
			bcdhex += asctohex(aschex.charAt(2 * i), aschex.charAt(2 * i + 1));
		return bcdhex;
	}

	/**
	 * des加密
	 * @param key 密钥
	 * @param data 明文数据 16进制且长度为16的整数倍
	 * @return 密文数据
	 */
	public static byte[] UnionDesEncrypt(byte key[], byte data[])
	{

		try
		{
			KeySpec ks = new DESKeySpec(key);
			SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
			SecretKey ky = kf.generateSecret(ks);

			Cipher c = Cipher.getInstance(DES);
			c.init(Cipher.ENCRYPT_MODE, ky);
			return c.doFinal(data);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * des解密
	 * @param key 密钥
	 * @param data 密文数据 16进制且长度为16的整数倍
	 * @return 明文数据
	 */
	public static byte[] UnionDesDecrypt(byte key[], byte data[])
	{

		try
		{
			KeySpec ks = new DESKeySpec(key);
			SecretKeyFactory kf = SecretKeyFactory.getInstance("DES");
			SecretKey ky = kf.generateSecret(ks);

			Cipher c = Cipher.getInstance(DES);
			c.init(Cipher.DECRYPT_MODE, ky);
			return c.doFinal(data);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 3des加密
	 * @param key 密钥
	 * @param data 明文数据 16进制且长度为16的整数倍
	 * @return 密文数据
	 */
	public static byte[] Union3DesEncrypt(byte key[], byte data[])
	{
		try
		{
			byte[] k = new byte[24];

			int len = data.length;
			if (data.length % 8 != 0)
			{
				len = data.length - data.length % 8 + 8;
			}
			byte[] needData = null;
			if (len != 0)
				needData = new byte[len];

			for (int i = 0; i < len; i++)
			{
				needData[i] = 0x00;
			}

			System.arraycopy(data, 0, needData, 0, data.length);

			if (key.length == 16)
			{
				System.arraycopy(key, 0, k, 0, key.length);
				System.arraycopy(key, 0, k, 16, 8);
			}
			else
			{
				System.arraycopy(key, 0, k, 0, 24);
			}

			KeySpec ks = new DESedeKeySpec(k);
			SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
			SecretKey ky = kf.generateSecret(ks);

			Cipher c = Cipher.getInstance(TriDes);
			c.init(Cipher.ENCRYPT_MODE, ky);
			return c.doFinal(needData);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * 3des解密
	 * @param key 密钥
	 * @param data 密文数据 16进制且长度为16的整数倍
	 * @return 明文数据
	 */
	public static byte[] Union3DesDecrypt(byte key[], byte data[])
	{
		try
		{
			byte[] k = new byte[24];

			int len = data.length;
			if (data.length % 8 != 0)
			{
				len = data.length - data.length % 8 + 8;
			}
			byte[] needData = null;
			if (len != 0)
				needData = new byte[len];

			for (int i = 0; i < len; i++)
			{
				needData[i] = 0x00;
			}

			System.arraycopy(data, 0, needData, 0, data.length);

			if (key.length == 16)
			{
				System.arraycopy(key, 0, k, 0, key.length);
				System.arraycopy(key, 0, k, 16, 8);
			}
			else
			{
				System.arraycopy(key, 0, k, 0, 24);
			}
			KeySpec ks = new DESedeKeySpec(k);
			SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
			SecretKey ky = kf.generateSecret(ks);

			Cipher c = Cipher.getInstance(TriDes);
			c.init(Cipher.DECRYPT_MODE, ky);
			return c.doFinal(needData);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}

	}

	/**
	 * 数据解密
	 * @param key 密钥 支持单倍和多倍密钥
	 * @param data 密文数据 16进制且长度为16的整数倍
	 * @return 明文数据
	 */
	public static String UnionDecryptData(String key, String data)
	{
		if ((key.length() != 16) && (key.length() != 32) && (key.length() != 48))
		{
			return (null);
		}
		if (data.length() % 16 != 0)
		{
			return "";
		}
		int lenOfKey = 0;
		lenOfKey = key.length();
		String strEncrypt = "";
		byte sourData[] = hex2byte(data);
		// byte sourData[] = data.getBytes();
		switch (lenOfKey)
		{
			case 16:
				byte deskey8[] = hex2byte(key);
				byte encrypt[] = UnionDesDecrypt(deskey8, sourData);
				strEncrypt = byte2hex(encrypt);
				break;
			case 32:
			case 48:
				String newkey1 = "";
				if (lenOfKey == 32)
				{
					String newkey = key.substring(0, 16);
					newkey1 = key + newkey;
				}
				else
				{
					newkey1 = key;
				}
				byte deskey24[] = hex2byte(newkey1);
				byte desEncrypt[] = Union3DesDecrypt(deskey24, sourData);
				strEncrypt = byte2hex(desEncrypt);
		}
		// return strEncrypt;
		return (aschex_to_bcdhex(strEncrypt, strEncrypt.length()));
	}

	/**
	 * 加密数据
	 * @param key 密钥 16进制且长度为16的整数倍
	 * @param data 明文数据 16进制且长度为16的整数倍
	 * @return 密文数据
	 */
	public static String UnionEncryptData(String key, String data)
	{
		if ((key.length() != 16) && (key.length() != 32) && (key.length() != 48))
		{
			return (null);
		}
		if (data.length() % 16 != 0)
		{
			return "";
		}
		int lenOfKey = 0;
		lenOfKey = key.length();
		String strEncrypt = "";
		// byte sourData[] = hex2byte(data);
		byte sourData[] = data.getBytes();
		switch (lenOfKey)
		{
			case 16:
				byte deskey8[] = hex2byte(key);
				byte encrypt[] = UnionDesEncrypt(deskey8, sourData);
				strEncrypt = byte2hex(encrypt);
				break;
			case 32:
			case 48:
				String newkey1 = "";
				if (lenOfKey == 32)
				{
					String newkey = key.substring(0, 16);
					newkey1 = key + newkey;
				}
				else
				{
					newkey1 = key;
				}
				byte deskey24[] = hex2byte(newkey1);
				byte desEncrypt[] = Union3DesEncrypt(deskey24, sourData);
				strEncrypt = byte2hex(desEncrypt);
				break;
		}
		return strEncrypt;
	}

	/*
	 * 功能：加解密Pin key 密钥值 pin 用于加密时为Pin明文，用于解密时为Pin密文 model 1时表示加密， 0时表示为解密
	 */
	public static String UnionEncryptAndDecryptPin(String key, String pin, int model)
	{
		String result = "";
		String tmpBuf = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
		String data = "";
		if (model == 1)
		{
			data = String.format("%02d%s", pin.length(), pin);
			if (data.length() % 16 != 0)
			{
				data += tmpBuf.substring(0, 16 - data.length() % 16);
			}
			result = UnionEncryptData(key, data);
		}
		else if (model == 0)
		{
			data = UnionDecryptData(key, pin);
			Integer len = new Integer(data.substring(0, 2));
			result = data.substring(2, len.intValue() + 2);
		}
		else
		{
			System.out.println("model is error");
		}
		return result;
	}

	public static void main(String[] args)
	{
		// String key = "0123456789ABCDEF";
		String key = "0123456789ABCDEFFEDCBA9876543210";
		String data = "111df16666";

		String encData = UnionEncryptAndDecryptPin(key, data, 1);
		System.out.println("encData = " + encData);

		String sourData = UnionEncryptAndDecryptPin(key, encData, 0);
		System.out.println("plainData = " + sourData);
	}
}
